/*******************************************************************************
 * 创建: 2025年09月30日
 * 作者: 水煮肉片饭(27185709@qq.com)
 * 描述: 音频模块
*******************************************************************************/
import { AudioSource, AudioClip, js, assetManager, sys, AssetManager } from "cc";
let _musicPlayer: AudioSource = new AudioSource();
let _musicOn: boolean = JSON.parse(sys.localStorage.getItem('musicOn')) ?? true;
let _soundPlayer: AudioSource = new AudioSource();
let _soundOn: boolean = JSON.parse(sys.localStorage.getItem('soundOn')) ?? true;
let _audioAssets: Object = js.createMap(true);
function _audioLoad(path: string): Promise<AudioClip> {
    return new Promise<AudioClip>(function (resolve) {
        if (path === null || path === undefined) { resolve(null); return; }
        let asset = _audioAssets[path];
        if (asset) { resolve(asset); return; }
        let index = path.indexOf('/');
        let bundleName = path.slice(0, index);
        let assetPath = path.slice(index + 1);
        ((callback: (bundle: AssetManager.Bundle) => void) => {
            let bundle = assetManager.getBundle(bundleName);
            if (bundle) { callback(bundle); return; }
            assetManager.loadBundle(bundleName, (err: Error, bundle: AssetManager.Bundle) => { callback(err ? null : bundle); })
        })((bundle: AssetManager.Bundle): void => {
            if (!bundle) { resolve(null); return; }
            bundle.load(assetPath, AudioClip, (err: Error, asset: AudioClip) => {
                resolve(err ? null : _audioAssets[path] = asset);
            });
        });
    });
}
Object.assign((globalThis as any).gi ||= {}, {
    musicPlay: function (pathOrClip: string | AudioClip = _musicPlayer.clip, isLoop: boolean = true, isRestart: boolean = false): Promise<void> {
        return new Promise<void>(async (resolve) => {
            if (!_musicOn || pathOrClip === '') { resolve(); return; }
            let clip = typeof pathOrClip === 'string' ? await _audioLoad(pathOrClip) : pathOrClip;
            if (!clip) { console.warn(`gi.musicPlay音乐播放失败！${pathOrClip}`); resolve(); return; }
            _musicPlayer.loop = isLoop;
            if (isRestart || _musicPlayer.state !== 1 || _musicPlayer.clip !== clip) {
                _musicPlayer.stop();
                _musicPlayer.clip = clip;
                _musicPlayer.play();
            }
            resolve();
        });
    },
    musicPause: function (): void { _musicPlayer.pause(); },
    musicResume: function (): void { (_musicPlayer.state === 2 || _musicPlayer.state === 4) && _musicPlayer.play(); },
    musicStop: function (): void { _musicPlayer.stop(); },
    soundPlay: function (pathOrClip: string | AudioClip, volumeScale: number = 1): Promise<void> {
        return new Promise<void>(async (resolve) => {
            if (!_soundOn || pathOrClip === '') { resolve(); return; }
            let clip = typeof pathOrClip === 'string' ? await _audioLoad(pathOrClip) : pathOrClip;
            if (!clip) { console.warn(`gi.soundPlay音效播放失败！${pathOrClip}`); resolve(); return; }
            _soundPlayer.playOneShot(clip, volumeScale);
            resolve();
        });
    },
    audioRelease: function (pathOrClip?: string | AudioClip): void {
        if (pathOrClip === undefined) { for (let path in _audioAssets) { this.audioRelease(path); } return; }
        let path = typeof pathOrClip === 'string' ? pathOrClip : Object.keys(_audioAssets).find(path => _audioAssets[path] === pathOrClip);
        if (!path || !_audioAssets[path]) return;
        assetManager.releaseAsset(_audioAssets[path]);
        delete _audioAssets[path];
    },
});
Reflect.defineProperty(gi, 'musicOn', {
    get: function (): boolean { return _musicOn; },
    set: function (val) {
        sys.localStorage.setItem('musicOn', JSON.stringify(_musicOn = !!val));
        _musicOn ? _musicPlayer.state !== 0 && gi.musicPlay() : gi.musicStop();
    },
});
Reflect.defineProperty(gi, 'musicVolume', {
    get: function (): number { return _musicPlayer.volume; },
    set: function (val) { _musicPlayer.volume = val; },
});
Reflect.defineProperty(gi, 'musicCurrentTime', {
    get: function (): number { return _musicPlayer.currentTime; },
    set: function (val) { _musicPlayer.currentTime = val ?? 0; },
});
Reflect.defineProperty(gi, 'musicDuration', {
    get: function (): number { return _musicPlayer.duration; },
    set: function (val) { console.error(`gi.musicDuration是只读属性，不允许主动赋值！${val}`); },
});
Reflect.defineProperty(gi, 'soundOn', {
    get: function (): boolean { return _soundOn; },
    set: function (val) { sys.localStorage.setItem('soundOn', JSON.stringify(_soundOn = !!val)); },
});
Reflect.defineProperty(gi, 'soundVolume', {
    get: function (): number { return _soundPlayer.volume; },
    set: function (val) { _soundPlayer.volume = val; },
});
declare global {
    module gi {
        /**音乐开关，默认值：true */
        let musicOn: boolean;
        /**音乐音量，取值范围：[0, 1]，默认值：1 */
        let musicVolume: number;
        /**音乐播放了多少秒 */
        let musicCurrentTime: number;
        /**音乐总时长多少秒，只读属性请勿主动赋值 */
        let musicDuration: number;
        /**音乐播放，pathOrClip可以填路径（从bundle包名开始填），也可以填AudioClip资源引用
         * isLoop是否循环，isRestart如果有音乐正在播放，是否强制重播 */
        function musicPlay(pathOrClip?: string | AudioClip, isLoop?: boolean, isRestart?: boolean): Promise<void>;
        /**音乐暂停，可通过musicResume继续播放 */
        function musicPause(): void;
        /**音乐恢复，只对暂停或中断的音乐有效 */
        function musicResume(): void;
        /**音乐停止 */
        function musicStop(): void;
        /**音效开关，默认值：true */
        let soundOn: boolean;
        /**音效音量，取值范围：[0, 1]，默认值：1 */
        let soundVolume: number;
        /**音效播放，pathOrClip可以填路径（从bundle包名开始填），也可以填AudioClip资源引用
         * volumeScale 单独调节该音效的音量，取值范围：[0, 1]，默认值：1 */
        function soundPlay(pathOrClip: string | AudioClip, volumeScale?: number): Promise<void>;
        /** 释放音频资源，pathOrClip可以填路径（从bundle包名开始填），也可以填AudioClip资源引用
         * 如果pathOrClip缺省，则释放所有音频资源*/
        function audioRelease(pathOrClip?: string | AudioClip): void;
    }
}